//
//  ClientSocket.m
//  CocoaAsyncSocketClient
//
//  Created by lixiaoyi on 2018/6/7.
//  Copyright © 2018年 lixiaoyi. All rights reserved.
//

#import "ClientSocket.h"
#import "ChatHeader.h"
#import "YZChatUtils.h"
#import "varint.h"
#import "YZChatUtils.h"
#import "ImMessage.pbobjc.h"
#import "YZUser.h"

@implementation ClientSocket

static ClientSocket *sharedSock = nil;
static dispatch_once_t onceToken;
+ (ClientSocket *)shareSocket {
//    static ClientSocket *sharedSock = nil;
//    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedSock = [[self alloc] init];
    });
    
    return sharedSock;
}

+ (void)attempDealloc {
    onceToken = 0;
    sharedSock = nil;
}

- (instancetype)init {
    self = [super init];
    if (self) {
//        self.socket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
        dispatch_queue_t myQueue =
            dispatch_queue_create("yingzi", DISPATCH_QUEUE_SERIAL);
        self.socket = [[GCDAsyncSocket alloc] initWithDelegate:self
                                                 delegateQueue:myQueue];
    }
    return self;
}

#pragma mark - GCDAsyncSocketDelegate
- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port {
    if (self.socketDelegate) {
        [self.socketDelegate clientSocket:sock didConnectToHost:host port:port];
    }
}

- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {
    if (self.socketDelegate) {
        [self.socketDelegate clientSocket:sock didReadData:data withTag:tag];
    }
}

- (void)clientSocketDidDisconnect:(GCDAsyncSocket *)sock
                        withError:(nullable NSError *)err {
    if (self.socketDelegate) {
        [self.socketDelegate clientSocketDidDisconnect:sock withError:err];
    }
}

#pragma mark - 连接
- (void)autoConnection {
    NSError *error = nil;
    self.connectd = [self.socket
                     connectToHost:self.socketHost
                     onPort:self.socketPort
                     withTimeout:-1 error:&error];
    
    if (self.connectd) {
        // 发送长连接conn
        [self doConn];
    }
}

// 长连接 tag->101
- (void)doConn{
    // 消息
    ImMessage *mess = [YZChatUtils createMessage:@"YZIMP" version:@"1.0" userId:[YZUser sharedInstance].uid userToken:[YZUser sharedInstance].token messageId:1 messageType:@"conn" messageTime:[[YZChatUtils getTimeInterval2] integerValue] termType:@"iOS" receiver:nil sender:nil ctrlMessageId:0 mediaType:nil playload:nil];
    
    // 序列化
    NSData *allData = [mess data];
    
    // 消息长度
    unsigned long long number = [allData length];
    char* str = calloc(7, sizeof(char));
    unsigned char bts;
    varint_encode(number, str, 7, &bts);
    NSData *headVarint = [NSData dataWithBytes:str length:bts];
    NSLog(@"headVarint>>>%@",headVarint);
    free(str);
    // 总个消息
    NSMutableData *totalData = [NSMutableData dataWithData:headVarint];
    [totalData appendData:allData];
    
    [self.socket writeData:totalData withTimeout:-1 tag:101];
}

#pragma mark - 断开连接
- (void)disConn {
    self.delegate = nil;
    [self.socket disconnect];
    self.socket = nil;
    self.connectd = NO;
    [self.connectTimer invalidate];
    self.connectTimer = nil;
}

#pragma mark - 发送ack
- (void)doAck:(int32_t)messId {
    // 消息
    ImMessage *mess = [YZChatUtils createMessage:@"YZIMP" version:@"1.0" userId:[YZUser sharedInstance].uid userToken:[YZUser sharedInstance].token messageId:messId messageType:@"ack" messageTime:[[YZChatUtils getTimeInterval2] integerValue] termType:@"iOS" receiver:nil sender:nil ctrlMessageId:messId mediaType:nil playload:nil];
    
    // 序列化
    NSData *allData = [mess data];
    
    // 消息长度
    unsigned long long number = [allData length];
    char* str = calloc(7, sizeof(char));
    unsigned char bts;
    varint_encode(number, str, 7, &bts);
    NSData *headVarint = [NSData dataWithBytes:str length:bts];
    NSLog(@"headVarint>>>%@",headVarint);
    free(str);
    // 总个消息
    NSMutableData *totalData = [NSMutableData dataWithData:headVarint];
    [totalData appendData:allData];
    
    [self.socket writeData:totalData withTimeout:-1 tag:0];
}

#pragma mark - 心跳
- (void)addTimer {
    self.connectTimer = [NSTimer scheduledTimerWithTimeInterval:HEART_TIME target:self selector:@selector(longConnectToSocket) userInfo:nil repeats:YES];
    
    [[NSRunLoop mainRunLoop] addTimer:self.connectTimer forMode:NSRunLoopCommonModes];
    [self.connectTimer fire];
}

- (void)longConnectToSocket {
    Byte heartByte[3] = {0x10,0x00,0x00};
    NSData *data = [NSData dataWithBytes:heartByte length:3];
    [self.socket writeData:data withTimeout:-1 tag:100];
    
    // 记录心跳发送的时间
    self.sendHeartDt = [NSDate date];
    
    NSTimeInterval interlTimer = [self.sendHeartDt timeIntervalSinceDate:self.receHearDt];
    if (interlTimer > HEART_TIME * 2) {
        NSLog(@"心跳失效，重新连接");
        // 重新连接
        dispatch_async(dispatch_get_main_queue(), ^{
            [self autoConnection];
        });
    }
}

@end
